/*
 * SPDX-License-Identifier: GPL-2.0
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 * Description:
 * Author: -
 * Create:
 */

#include "ossl_knl.h"
#include "hiudk3.h"
#include "hiudk_internal.h"
int hiudk_attach_nic(struct hinic3_lld_dev *lld_dev)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_attach_nic != NULL))) {
        return ops->dev_ops.hiudk_attach_nic(lld_dev);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_attach_nic);

int hiudk_get_chip_name(struct hinic3_lld_dev *lld_dev, char *chip_name, u16 max_len)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_get_chip_name != NULL))) {
        return ops->dev_ops.hiudk_get_chip_name(lld_dev, chip_name, max_len);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_get_chip_name);

int hiudk_attach_service(const struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_attach_service != NULL))) {
        return ops->dev_ops.hiudk_attach_service(lld_dev, type);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_attach_service);

void hiudk_detach_nic(const struct hinic3_lld_dev *lld_dev)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_detach_nic != NULL))) {
        return ops->dev_ops.hiudk_detach_nic(lld_dev);
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_detach_nic);

void hiudk_detach_service(const struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_detach_service != NULL))) {
        return ops->dev_ops.hiudk_detach_service(lld_dev, type);
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_detach_service);


/**
 * @brief hiudk_get_ppf_lld_dev - get ppf lld device by current function's lld device
 * @param lld_dev: current function's lld device
 *
 * The value of lld_dev reference increases when lld_dev is obtained. The caller needs
 * to release the reference by calling lld_dev_put.
 */
struct hinic3_lld_dev *hiudk_get_ppf_lld_dev(struct hinic3_lld_dev *lld_dev)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return NULL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_get_ppf_lld_dev != NULL))) {
        return ops->dev_ops.hiudk_get_ppf_lld_dev(lld_dev);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_get_ppf_lld_dev);

/**
 * @brief hiudk_get_ppf_lld_dev_unsafe - get ppf lld device by current function's lld device
 * @param lld_dev: current function's lld device
 *
 * hiudk_get_ppf_lld_dev_unsafe() is completely analogous to hiudk_get_ppf_lld_dev(),
 * The only difference is that the reference of lld_dev is not increased when lld_dev is obtained.
 *
 * The caller must ensure that ppf's lld_dev will not be freed during the remove process
 * when using ppf lld_dev.
 */
struct hinic3_lld_dev *hiudk_get_ppf_lld_dev_unsafe(struct hinic3_lld_dev *lld_dev)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return NULL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_get_ppf_lld_dev_unsafe != NULL))) {
        return ops->dev_ops.hiudk_get_ppf_lld_dev_unsafe(lld_dev);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_get_ppf_lld_dev_unsafe);

/**
 * @brief hiudk_get_uld_dev - get uld device by lld device
 * @param lld_dev: lld device
 * @param type: uld service type
 *
 * The value of uld_dev reference increases when uld_dev is obtained. The caller needs
 * to release the reference by calling uld_dev_put.
 */
void *hiudk_get_uld_dev(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        return NULL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_get_uld_dev != NULL))) {
        return ops->dev_ops.hiudk_get_uld_dev(lld_dev, type);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_get_uld_dev);

/**
 * @brief hiudk_get_uld_dev_unsafe - get uld device by lld device
 * @param lld_dev: lld device
 * @param type: uld service type
 *
 * hiudk_get_uld_dev_unsafe() is completely analogous to hiudk_get_uld_dev(),
 * The only difference is that the reference of uld_dev is not increased when uld_dev is obtained.
 *
 * The caller must ensure that uld_dev will not be freed during the remove process
 * when using uld_dev.
 */
void *hiudk_get_uld_dev_unsafe(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return NULL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_get_uld_dev_unsafe != NULL))) {
        return ops->dev_ops.hiudk_get_uld_dev_unsafe(lld_dev, type);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_get_uld_dev_unsafe);


int hiudk_set_vf_load_state(struct hinic3_lld_dev *lld_dev, bool vf_load_state)
{
    struct pci_dev *pdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return -EINVAL;
    }

    pdev = lld_dev->pdev;
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_set_vf_load_state != NULL))) {
        return ops->dev_ops.hiudk_set_vf_load_state(pdev, vf_load_state);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_set_vf_load_state);

int hiudk_set_vf_service_load(struct hinic3_lld_dev *lld_dev, u16 service, bool vf_srv_load)
{
    struct pci_dev *pdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return -EINVAL;
    }

    pdev = lld_dev->pdev;
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_set_vf_service_load != NULL))) {
        return ops->dev_ops.hiudk_set_vf_service_load(pdev, service, vf_srv_load);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_set_vf_service_load);

int hiudk_set_vf_service_state(struct hinic3_lld_dev *lld_dev, u16 vf_func_id, u16 service, bool en)
{
    struct pci_dev *pdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return -EINVAL;
    }

    pdev = lld_dev->pdev;
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_set_vf_service_state != NULL))) {
        return ops->dev_ops.hiudk_set_vf_service_state(pdev, vf_func_id, service, en);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_set_vf_service_state);

/**
 * @brief uld_dev_hold - get reference to uld_dev
 * @param lld_dev: lld device
 * @param type: uld service type
 *
 * Hold reference to uld device to keep it from being freed
 */
void hiudk_uld_dev_hold(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_uld_dev_hold != NULL))) {
        ops->dev_ops.hiudk_uld_dev_hold(lld_dev, type);
        return;
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_uld_dev_hold);

/**
 * @brief uld_dev_put - release reference to lld_dev
 * @param dev: lld device
 * @param type: uld service type
 *
 * Release reference to uld device to allow it to be freed
 */
void hiudk_uld_dev_put(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(lld_dev == NULL)) {
        pr_err("lld_dev is NULL! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(lld_dev->hwdev);
    if (likely((ops != NULL) && (ops->dev_ops.hiudk_uld_dev_put != NULL))) {
        ops->dev_ops.hiudk_uld_dev_put(lld_dev, type);
        return;
    }
    pr_err("ops is NULL! \n");
    return;
}
EXPORT_SYMBOL(hiudk_uld_dev_put);
